<?php
require_once "Zend/Tokenizer/Interface.php";

/**
 * @category   Zend
 * @package    Zend_Tokenizer
 * @copyright  Salomon BRYS
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 *
 * This tokenizer gives tokens representing a line from the stream.
 */
abstract class Zend_Tokenizer_String_Abstract implements Zend_Tokenizer_Interface
{
	/**
	 * @var Zend_Tokenizer_Interface
	 */
	protected $_producer;

	/**
	 * @var string
	 */
	protected $_data;

	/**
	 * Constructor
	 *
	 * @param Zend_Tokenizer_Interface $producer
	 */
	public function __construct(Zend_Tokenizer_Interface $producer)
	{
		if (!$producer->isStringToken()) {
			require_once 'Zend/Exception.php';
			throw new Zend_Exception("Zend_Tokenizer_String_* needs a string token producer.");
		}
		$this->_producer = $producer;
	}

	/**
	 * Add the buffered data not tokenized yet.
	 * Used to transfer data when tokenizer is changing on the fly.
	 *
	 * @return string
	 */
	public function getRawData()
	{
		return $this->_data . $this->_producer->getRawData();
	}

	/**
	 * return wether there's at least one token ready.
	 *
	 * @return bool
	 */
	public function hasToken()
	{
		$this->_fillData();
		return $this->checkHasToken($this->_data);
	}

	/**
	 * return wether there's at least one token ready.
	 *
	 * @return bool
	 */
	abstract protected function checkHasToken($data);

	/**
	 * Return the next token.
	 *
	 * @return mixed
	 */
	public function getToken()
	{
		$this->_fillData();
		if (!$this->checkHasToken($this->_data)) {
			return null;
		}
		$ret = $this->extractFirstToken($this->_data);
		return $ret;
	}

	/**
	 * Return the next token.
	 *
	 * @return mixed
	 */
	abstract protected function extractFirstToken(&$data);

	/**
	 * Fill the _data propriety with producer's string tokens.
	 */
	protected function _fillData()
	{
		while ($this->_producer->hasToken()) {
			$this->_data .= $this->_producer->getToken();
		}
	}

	/**
	 * Return wether it is the of the stream.
	 *
	 * @return bool
	 */
	public function isEndOfStream()
	{
		return $this->_producer->isEndOfStream();
	}

	/**
	 * Return wether the tokenizer produces string tokens
	 *
	 * @return bool
	 */
	public function isStringToken()
	{
		return true;
	}

	/**
	 * Get the 'first' tokenizer. The producer.
	 * If a decorator, returns the decorated tokenizer.
	 * If a producer, returns itself.
	 *
	 * @return Zend_Tokenizer_Interface
	 */
	public function getProducer()
	{
		return $this->_producer->getProducer();
	}
}
